package com.fer.tankr.controllers.level;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.andengine.engine.camera.Camera;
import org.andengine.entity.scene.Scene;
import org.andengine.extension.physics.box2d.PhysicsWorld;
import org.andengine.opengl.vbo.VertexBufferObjectManager;

import android.util.Log;

import com.fer.andenginemvc.api.gameObjects.GameBorder;
import com.fer.andenginemvc.api.gameObjects.GameObject;
import com.fer.andenginemvc.api.gameObjects.Powerup;
import com.fer.tankr.AssetManagerImpl;
import com.fer.tankr.huds.IHud;
import com.fer.tankr.models.Bullet;
import com.fer.tankr.models.Tank;
import com.fer.tankr.models.enemies.BoxFuckerEnemy;
import com.fer.tankr.models.enemies.CoinerEnemy;
import com.fer.tankr.models.enemies.Enemy;
import com.fer.tankr.models.enemies.FatGuyEnemy;
import com.fer.tankr.models.enemies.LeftRightEnemy;
import com.fer.tankr.models.enemies.UpDownEnemy;
import com.fer.tankr.models.obstacles.Crate;
import com.fer.tankr.models.obstacles.SolidCrate;
import com.fer.tankr.models.powerups.BulletPowerup;
import com.fer.tankr.models.powerups.ChangeLevel;
import com.fer.tankr.models.powerups.ChangeLevel.IChangeLevelHandler;
import com.fer.tankr.models.powerups.Coin;

public class Level{

	public final static String SPLITTER = ";";
	
	private PhysicsWorld physWorld;
	private VertexBufferObjectManager vbom;
	private Scene scene;
	public int level;
	private Camera camera;
	private IHud hud;
	private int coins;
	
	private AssetManagerImpl assetManager;
	
	private ArrayList<LevelData> levels;
	private int blockWidth;
	private int blockHeight;
	
	private IChangeLevelHandler handler;
	
	//Entities
	public Tank tank;
	
	public Level(IChangeLevelHandler handler,VertexBufferObjectManager vbom2,
			PhysicsWorld physWorld2, Scene scene2, Camera camera, IHud hud, ArrayList<LevelData> levels, AssetManagerImpl assetManager) {
		this.level = 1;
		this.vbom = vbom2;
		this.physWorld = physWorld2;
		this.scene = scene2;
		this.camera = camera;
		this.hud = hud;
		this.levels = levels;
		blockHeight = 32;
		blockWidth = 32;
		this.assetManager = assetManager;
		this.handler = handler;
		initTank();
	}
	
	
	public void initLevel(int level) {
		
		this.level = level;
		coins = 0;
		try {
			Collection<GameObject<?>> gos = loadLevel(level);
			for (GameObject<?> gameObject : gos) {
				
				if(!gameObject.entity.hasParent())
				{
					this.scene.attachChild(gameObject.entity);
				}
				if (gameObject instanceof Coin)
				{
					coins++;
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		hud.setTotal(coins);
		Log.i("Level", "Level "+level+" loaded with "+coins +" coins");
	}
	
	public boolean nextLevel()
	{
		level++;
		tearDown();
		if (level <= levels.size())
		{
			initLevel(level);
			return true;
		}
		else
		{
			return false;
		}
	}

	
	public void initTank() {
		tank = new Tank(physWorld, vbom,hud, assetManager.tankBodyTexture, assetManager.tankCannonTexture);
		scene.attachChild(tank.entity);
		scene.attachChild(tank.cannon);
	}

	public void tearDown() {
		Collection<GameObject<?>> gos = new ArrayList<GameObject<?>>(GameObject.bodyMap.values());
		for (GameObject<?> go : gos) {
			if (go instanceof Bullet || go instanceof Powerup || go instanceof Enemy || go instanceof Crate|| go instanceof GameBorder)
			{
				go.die();
			}
		}
		tank.resetTank();
		
	}

	public boolean reduceCoins() {
		coins--;
		if (coins<=0)
		{
			return true;
		}
		return false;
	}
	
	public int getCoins() {
		return coins;
	}


	public List<GameObject<?>> loadLevel(int level) throws IOException
	{
		List<GameObject<?>> gos = new ArrayList<GameObject<?>>();
		
		LevelData levelData = levels.get(level-1);
		Collection<String> lines = levelData.getLines();
		int row = 0;
		int col = 0;
		for(String line : lines)
		{
			String[] data = line.split(SPLITTER);
			col = 0;
			for (String string : data) {
				
				String gameObject = string;
				GameObject<?> go = getObject(row,col,gameObject);
				
				if (go != null)
				{
					go.body.setTransform(col, row, 0);
					gos.add(go);
				}
				
				col++;
			}
			row++;
			
		}
		tank.setBullets(levelData.getAmmo());
		tank.setLives(levelData.getLives());
		
		return gos;
	}

	private GameObject<?> getObject(int row, int col, String gameObject) {
		float x = 0;//col*blockWidth;
		float y = 0;//row*blockHeight;
		if (gameObject.equals("BS"))
		{
			return new SolidCrate(physWorld, vbom, x, y, blockWidth, blockHeight, assetManager.crateSolidTexture);
		}
		else if (gameObject.equals("BP"))
		{
			return new Crate(physWorld, vbom, x, y, blockWidth, blockHeight, assetManager.cratePushTexture);
		}
		else if (gameObject.equals("TT"))
		{
			tank.body.setTransform(1, 1, 0);
			return tank;
		}
		else if (gameObject.equals("EB"))
		{
			return new BoxFuckerEnemy(physWorld, vbom, x, y, tank, assetManager.cratePushTexture, assetManager.boxFucker);
		}
		else if (gameObject.equals("EC"))
		{
			return new CoinerEnemy(physWorld, vbom, x, y, tank.entity, assetManager.coinsTexture,assetManager.coinFuckerTexture);
		}
		else if (gameObject.equals("EF"))
		{
			return new FatGuyEnemy(physWorld, vbom, x, y, tank.entity, camera, assetManager.smileFucker);
		}
		else if (gameObject.equals("PC"))
		{
			return new Coin(physWorld, vbom, x, y, assetManager.coinsTexture);
		}
		else if (gameObject.equals("PB"))
		{
			return new BulletPowerup(physWorld, vbom, x, y, assetManager.bulletsTexture);
		}
		else if (gameObject.equals("EL"))
		{
			return new LeftRightEnemy(physWorld, vbom, x, y, assetManager.leftRightEnemy);
		}
		else if (gameObject.equals("EU"))
		{
			return new UpDownEnemy(physWorld, vbom, x, y, assetManager.upDownEnemy);
		}
		else if (gameObject.matches("[0-9]+"))
		{
			Log.i("WOW CHECK IT OUT",  gameObject);
			ChangeLevel changeLevel =  new ChangeLevel(physWorld, vbom, x, y, assetManager.cratePushTexture, Integer.parseInt(gameObject));
			changeLevel.setChangeLevelHandler(handler);
			return changeLevel;
		}
		else if (gameObject.equals("  "))
		{
			//return new BulletPowerup(physWorld, vbom, x, y);
			return null;
		}
		else 
		{
			throw new RuntimeException("Block '"+gameObject+"' unknown");
		}
	}


	public void reset() {
		tearDown();
		initLevel(level);
	}
}
